package org.example.mutithread.future;

import org.example.pattern.strategy.Result;
import org.example.pattern.strategy.Strategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class CompletableFutureUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(CompletableFutureUtil.class);

    private static final Random random = new Random();


    public <T> Result<T> waitAll(List<Strategy<T>> strategys) {
        List<CompletableFuture<Result<T>>> futures = new ArrayList<>();
        for (Strategy strategy : strategys) {
            futures.add(createFutureForStrategy(strategy));
        }

        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));

        CompletableFuture<List<Result<T>>> resultsFuture = allFutures.thenApply(v ->
                futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList())
        );

        return processResults(resultsFuture);
    }

    private <T> CompletableFuture<Result<T>> createFutureForStrategy(Strategy<T> strategy) {
        return CompletableFuture.supplyAsync(() -> {
            LOGGER.info("Operation {} is running...", strategy.getName());
            Result<T> result = null;
            try {
                result = strategy.validate();
            } catch (Exception e) {
                LOGGER.error("Operation interrupted", e);
                result = Result.result(-1, "future"); // 保持返回错误结果的逻辑，但增加了日志记录
            }
            LOGGER.info("Operation {} is finished...result={}", strategy.getName(), result);
            return result;
        });
    }

    private <T> Result<T> processResults(CompletableFuture<List<Result<T>>> resultsFuture) {
        Result<T> result = Result.result(200, "ALL success");
        try {
            List<Result<T>> results = resultsFuture.get();
            for (Result<T> res : results) {
                if (res.getCode() != 200) {
                    result.setCode(-1);
                    result.setMsg("fail");
                    result.putError(res.getCode(), res.getMsg());
                }
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 重新设置中断状态
            LOGGER.error("waitAll interrupted", e);
        } catch (Exception e) {
            Throwable cause = e.getCause(); // 获取原始异常
            LOGGER.error("waitAll error", cause != null ? cause : e);
        }
        return result;
    }


}
